%!Tex Program = xelatex
%\documentclass[a4paper]{article}
\documentclass[a4paper]{ctexart}
\usepackage{xltxtra}
\usepackage{listings}
\usepackage{float}
%\setmainfont[Mapping=tex-text]{AR PL UMing CN:style=Light}
%\setmainfont[Mapping=tex-text]{AR PL UKai CN:style=Book}
%\setmainfont[Mapping=tex-text]{WenQuanYi Zen Hei:style=Regular}
%\setmainfont[Mapping=tex-text]{WenQuanYi Zen Hei Sharp:style=Regular}
%\setmainfont[Mapping=tex-text]{AR PL KaitiM GB:style=Regular} 
%\setmainfont[Mapping=tex-text]{AR PL SungtiL GB:style=Regular} 
%\setmainfont[Mapping=tex-text]{WenQuanYi Zen Hei Mono:style=Regular} 

\usepackage{geometry}
\geometry{a4paper,scale=0.75}
\title{继续熟悉Latex和Shell基础}
\author{没有shell基础的萌新:周川迪}
\date{\today}
\begin{document}
\maketitle
\pagestyle{empty}

\section{控制结构}
Shell 有一组控制结构，类似其他程序设计语言。

\subsection{if语句}
if语句根据某个命令（condition）的执行结果进行测试，结果为真执行then后面的语句，反之执行else后面的。示例：
\begin{lstlisting}[language=sh]
if [ $timeofday = "yes" ]; then
    echo "Good morning."
else
    # commands
fi
\end{lstlisting}

注意到 if 和 condition、condition 和 then、then 和命令块之间都有一个空格，这是推荐的书写习惯。空格的存在有助于增强代码的可读性，并避免解析错误。

例如，如果忽略了空格，写成以下形式，会导致语法错误：
\begin{lstlisting}[language=sh]
if[condition];then
    # commands when condition is true
fi
\end{lstlisting}

\subsection{elif语句}
elif 是在 Shell 脚本中用于表示 "else if" 的关键字。它可以用于多个条件的判断。

elif 通常与 if 和 else 关键字一起使用，形成如下结构：
\begin{lstlisting}[language=sh]
if condition1; then
    # commands when condition1 is true
elif condition2; then
    # commands when condition1 is false and condition2 is true
else
    # commands when both condition1 and condition2 are false
fi
\end{lstlisting}

\subsection{if语句中condition的变量为空怎么办}
1.1的示例中timeofday是个字符串，它如果是空（如用户没有输入直接回车），那条件
\begin{lstlisting}[language=sh]
if [ $timeofday = "yes" ];
\end{lstlisting}
 会变成：
\begin{lstlisting}[language=sh]
if [ = "yes" ];
\end{lstlisting}
而这不是一个合法的条件，为避免须给变量加上引号，如
\begin{lstlisting}[language=sh]
if [ ”$timeofday“ = "yes" ];
\end{lstlisting}
那这就能成为一个合法的条件：
\begin{lstlisting}[language=sh]
if [ ""= "yes" ];
\end{lstlisting}

\subsection{for语句}
for结构可以循环处理一组值。这组值可以在程序里被列出。结构：
\begin{lstlisting}[language=sh]
for variable in item1 item2 item3 ...; do
    # commands
done
\end{lstlisting}
更常见的是使用通配符拓展，比如用*拓展当前目录中的所有文件。比如只处理当前目录所有f开头以.sh结尾的文件：
\begin{lstlisting}[language=sh]
for file in $(ls f*.sh); do
    # commands using "$file"
done
\end{lstlisting}
其中去掉f则是所有.sh文件，再去掉.sh则是所有文件。

\subsection{while语句}
while 是一种循环结构，它会在条件为真时重复执行一系列命令。结构：
\begin{lstlisting}[language=sh]
while condition; do
    # commands
done
\end{lstlisting}

\subsection{until语句}
与 while 循环相反，until 循环会在条件为假时执行，直到条件变为真为止。结构：
\begin{lstlisting}[language=sh]
until condition; do
    # commands
done
\end{lstlisting}

\subsection{case语句}

case 是一种条件语句，用于根据不同的值执行不同的命令。它可以替代多个 if-elif-else 的嵌套结构，使代码更清晰和简洁。结构：
\begin{lstlisting}[language=sh]
case value in
    pattern1)
        # commands ;;
    pattern2)
        # commands ;;
    pattern3)
        # commands ;;
    *)
        # default commands ;;
esac
\end{lstlisting}

在 case 语句中，value 是要匹配的值。然后，根据每个模式（pattern）来执行对应的命令块。如果模式匹配成功，则执行相应的命令，并使用 ;; 表示该分支结束。如果没有匹配到任何模式，则执行 *) 分支中的命令，表示默认情况。

\subsection{AND列表}
在Shell中，你可以使用逻辑与操作符 \& 将多个命令连接成一个“AND列表”。后续的命令只有在前面的命令成功执行（返回true）时才会被执行。有一条返回false后面的都不执行。其语法为：
\begin{lstlisting}[language=sh]
command1 && command2 && command3
\end{lstlisting}

\subsection{OR列表}
在Shell中，你可以使用逻辑与操作符 || 将多个命令连接成一个“OR列表”它将持续执行一系列命令知道有一条成功执行为止，其后的命令将不执行。其语法为：
\begin{lstlisting}[language=sh]
command1 || command2 || command3
\end{lstlisting}

可以将 \&\& 和||结合起来使用。 

\subsection{语句块}
在某些只允许使用单个语句的地方使用多条语句，可以将它们括在{}中来构造一个语句块。

\section{函数}
下面是定义和使用函数的一般语法：
\begin{lstlisting}[language=sh]
function_name() {
    # 函数体（包含一系列命令）
}
function_name  # 调用函数
\end{lstlisting}
注意调用函数前必须先定义。

函数也可以接有参数。在函数体内使用 \$*、\$@、\$1等参数，当函数被调用时，脚本程序的位置参数会被替换为函数的参数，执行后恢复为它们原先的值。示例：
\begin{lstlisting}[language=sh]
greet() {
    echo "Hello, $1!"
}
greet "John"
\end{lstlisting}
函数还可以通过return具有返回值。还可以echo一个字符串并捕获其结果。示例：\begin{lstlisting}[language=sh]
add() {
    local sum=$(($1 + $2))
    echo $sum
}
result=$(add 3 4)
echo "The sum is: $result"
\end{lstlisting}
输出:The sum is: 7

\section{命令}
shell脚本内部可以执行外部（“普通”）命令和内部（内“内置”）命令这两类命令。
\subsection{break命令}
break 命令用于终止循环语句的执行，通常用于 for、while 和 until 循环中。当 break 命令被执行时，循环会立即结束，并且程序流程会跳出当前循环的代码块（默认只跳出一层循环），继续执行循环之后的代码。

\subsection{continue命令}
continue命令用于跳过当前循环中剩余的代码，并继续下一次循环迭代。

\subsection{:命令}
: 是一个空命令，是内置命令。它偶尔会被用于简化条件逻辑，相当于true，运行快但可读性差。

: 命令的主要作用是在某些情况下充当一个空代码块，以保持脚本的结构完整性或满足语法要求。它常用于以下情况：
\begin{itemize}
    \item[$\bullet$]在脚本中占位，以便稍后填充实际的代码逻辑。
    \item[$\bullet$]忽略某些条件下的代码执行，但需保持代码块的结构完整。
\end{itemize}
示例：
\begin{lstlisting}[language=sh]
# 使用 : 作为空代码块
if [ $condition ]; then
    :
else
    command1
    command2
fi

# 使用 : 进行占位
function my_function() {
    # : 在这里占位，稍后填充函数代码
    :
}
\end{lstlisting}

\subsection{.命令}
.（点号）是一个特殊命令，用于在当前Shell环境中执行指定的脚本文件。示例：

\begin{lstlisting}[language=sh]
#!/bin/bash

# 首先你有这个script.sh脚本文件：
message="Hello, World!"
echo "This is a script file."
\end{lstlisting}
然后在另一个Shell会话中运行执行 . script.sh 命令后，脚本文件script.sh中的命令将会在当前Shell环境中执行。因此，脚本中的echo语句将输出" This is a script file."，并且message变量将在当前会话中可用。

\subsection{echo命令}
echo命令是一种在Shell中输出文本或变量值的常用方法。它将其参数作为文本输出到标准输出（通常是终端）。示例：
\begin{lstlisting}[language=sh]
# 输出文本
echo "Hello, World!"

# 输出变量值
name="Alice"
echo "My name is $name."

# -n：不在输出末尾添加换行符，即不换行。
echo -n "Hello, "
echo "World!"

# -e：启用特殊字符的解释，如\n表示换行，\t表示制表符等。
echo -e "Line 1\nLine 2\tTab"

# -E：禁用特殊字符的解释，直接输出字符本身。
echo -E "\nThis is a normal text."
\end{lstlisting}

\subsection{eval命令}
eval命令允许你对参数求值。示例：
\begin{lstlisting}[language=sh]
# 通过变量执行命令
command="ls -l"
eval $command

# 字符串拼接执行命令
cmd1="echo Hello,"
cmd2="World!"
eval "$cmd1 $cmd2"

# 动态生成命令并执行
for i in {1..5}; do
    command="echo Number: $i"
    eval $command
done
\end{lstlisting}

\subsection{exec命令}
exec是一个Shell内建命令，用于以指定的命令替换当前正在运行的Shell进程。它通常用于在脚本中切换执行的程序或重定向标准输入/输出。示例：
\begin{lstlisting}[language=sh]
exec wall "Thanks"
\end{lstlisting}
脚本中该命令会用wall命令替换当前的shell。脚本程序中exec后面的代码都不执行，因为执行这个脚本的shell已经不存在了。

\subsection{exit n命令}
exit n是一个Shell命令，用于终止当前正在运行的Shell进程，并返回一个退出状态码给调用该Shell进程的父进程。

退出状态码0表示成功，1-125是脚本程序可以使用的错误代码。其余数字具有保留含义。

\subsection{export命令}
export命令将作为它参数的变量导出到该shell后续调用所有的脚本中，并使其在后续所有子shell中有效。示例：

脚本程序export2：
\begin{lstlisting}[language=sh]
echo "$foo$"
echo "$bar$"
\end{lstlisting}
脚本程序export1，其结尾调用export2
\begin{lstlisting}[language=sh]
foo="1"
export bar="2"
\end{lstlisting}
运行export1，则输出2。

\subsection{expr命令}
expr命令将它的参数当作一个表达式进行求值。示例：
\begin{lstlisting}[language=sh]
x=`expr $x + 1`
\end{lstlisting}
反引号``字符将x取值为命令expr \$x + 1的执行结果。也可用\$()代替反引号``

expr可以完成许多表达式求值运算，如表\ref{table:expr}
\begin{table}[h!]
  \caption{expr命令的求值计算}
  \label{table.expr}
\centering
\begin{tabular}{|c|c|}
\hline
表达式求值 & 说明 \\
\hline
expr1 | expr2 & 如果expr1非0，则等于expr1，否则等于expr2\\
\hline
expr1 \& expr2 & 只要有一个表达式等于0，则等于0，否则等于expr1\\
\hline
expr1 = expr2 & 等于\\
\hline
expr1 > expr2 & 大于\\
\hline
expr1 >= expr2 & 大于等于\\
\hline
expr1 < expr2 & 小于\\
\hline
expr1 < expr2 & 小于等于\\
\hline
expr1 != expr2 & 不等于\\
\hline
expr1 + expr2 & 加法\\
\hline
expr1 - expr2 & 减法\\
\hline
expr1 * expr2 & 乘法\\
\hline
expr1 / expr2 & 除法\\
\hline
expr1 \% expr2 & 取余\\
\hline
\end{tabular}
\end{table}

\subsection{printf命令}
只有最新版本的shell才提供printf命令。语法是：
\begin{lstlisting}[language=sh]
printf "format string" parameter1 parameter2 ...
\end{lstlisting}
类似于C但不支持浮点数。格式字符串中除了\%和\\以外的所有字符都按原样输出，它支持的转义序列如表\ref{table:printf1}
\begin{table}[h!]
  \caption{printf的转义序列}
  \label{table.printf1}
\centering
\begin{tabular}{|c|c|}
\hline
转义序列 & 说明 \\
\hline
$\backslash$" & 双引号\\
\hline
$\backslash$$\backslash$ & 反斜线字符\\
\hline
$\backslash$ a & 报警（响铃或蜂鸣）\\
\hline
$\backslash$ b & 退格字符\\
\hline
$\backslash$ c & 取消进一步的输出\\
\hline
$\backslash$ f & 进纸换页字符\\
\hline
$\backslash$ n & 换行符\\
\hline
$\backslash$ r & 回车符\\
\hline
$\backslash$ t & 制表符\\
\hline
$\backslash$ v & 垂直制表符\\
\hline
$\backslash$ ooo & 八进制值ooo表示的单个字符\\
\hline
$\backslash$ xHH & 十进制值HH表示的单个字符\\
\hline
\end{tabular}
\end{table}

还有字符转换限定符，如表\ref{table:printf2}
\begin{table}[h!]
  \caption{printf的字符转换限定符}
  \label{table.printf2}
\centering
\begin{tabular}{|c|c|}
\hline
字符转化限定符 & 说明 \\
\hline
d & 输出一个十进制数字\\
\hline
c & 输出一个字符\\
\hline
s & 输出一个字符串\\
\hline
\% & 输出一个\%字符\\
\hline
\end{tabular}
\end{table}

\subsection{return命令}
return命令使函数返回。前面有提到：return 命令有一个数值参数，是该函数返回值；若没有指定参数，return命令活人返回最后一条命令的退出码。

\subsection{set命令}
set命令为shell设置参数变量，还可以通过set命令和它的参数来控制shell的执行方式。格式：
\begin{lstlisting}[language=sh]
set variable
\end{lstlisting}

\subsection{shift命令}
shift命令把所有参数左移一个位置，使\$2变成\$1，使\$3变成\$2，以此类推，但原来的\$1被丢弃而\$0不变。shift一般单独使用。

\subsection{trap命令}
trap命令有两个参数，第一个参数使接收到指定信号时将要采取的行动，第二个参水是要处理的信号名：
\begin{lstlisting}[language=sh]
trap command signal
\end{lstlisting}

表\ref{table:signal}列出了一些能被捕获的比较重要的信号（括号中的数字是对应的信号序号）：
\begin{table}[h!]
  \caption{信号}
  \label{table.signal}
\centering
\begin{tabular}{|c|c|}
\hline
信号 & 说明 \\
\hline
HUP(1) & 挂起，通常因终端掉线或用户退出而引发 \\
\hline
INT(2) & 中断，通常因按下Ctrl+C组合键而引发 \\
\hline
QUIT(3) & 退出，通常因按下Ctrl+$\backslash$组合键而引发 \\
\hline
ABRT(6) & 中止，通常因某些严重的执行错误引发 \\
\hline
ALRM(14) & 报警，通常用来处理超时 \\
\hline
TERM(15) & 终止，通常在系统关机时发送 \\
\hline
\end{tabular}
\end{table}

\subsection{unset命令}
unset命令与set命令相对，用于从Shell中移除指定的变量或函数。格式：
\begin{lstlisting}[language=sh]
unset variable
\end{lstlisting}

\subsection{find命令}
find 命令可以在系统中搜索文件，支持各种搜索条件和操作选项。基本语法：
\begin{lstlisting}[language=sh]
find <path> <expression>
\end{lstlisting}
示例：
\begin{itemize}

\item[$\bullet$]  查找特定文件
\begin{lstlisting}[language=sh]
find /path/to/search -name filename
# 这个命令将在指定路径 /path/to/search 下（下同）
# 递归查找文件名为 filename 的文件。
\end{lstlisting}

\item[$\bullet$]  查找特定类型的文件
\begin{lstlisting}[language=sh]
find /path/to/search -type f
# 递归查找所有普通文件。
\end{lstlisting}

\item[$\bullet$]  查找特定目录
\begin{lstlisting}[language=sh]
find /path/to/search -type d -name dirname
#递归查找目录名为 dirname 的目录。

\end{lstlisting}

\item[$\bullet$]  根据时间进行搜索
\begin{lstlisting}[language=sh]
find /path/to/search -type f -mtime +7
# 递归查找最近修改时间超过7天的文件
\end{lstlisting}

\item[$\bullet$]  进行操作grep
\begin{lstlisting}[language=sh]
find /path/to/search -type f -exec command {} \;
# 递归查找文件，并对每个文件执行command 命令。
# {} 表示匹配的文件名，\; 表示命令结束。
\end{lstlisting}

\end{itemize}

\subsection{grep命令}
grep 命令在文件中搜索字符串，支持各种选项和参数。基本语法：
\begin{lstlisting}[language=sh]
grep [options] pattern [files]
\end{lstlisting}
其中pattern是要搜索的模式，可以是字符串或正则表达式。files是要搜索的文件，可以是一个或多个文件。如果未指定文件，则默认从标准输入进行搜索。而一些主要选项，即[options]，如表\ref{table:grep}
\begin{table}[h!]
  \caption{grep选项}
  \label{table.grep}
\centering
\begin{tabular}{|c|c|}
\hline
选项 & 含义 \\
\hline
-c & 输出匹配行的数目，而不是输出匹配的行 \\
\hline
-E & 启用扩展表达式 \\
\hline
-h & 取消每个输出行的普通前缀，即匹配查询模式的文件名 \\
\hline
-i & 忽略大小写 \\
\hline
-l & 只列出包含匹配行的文件名，而不是输出真正的匹配行 \\
\hline
-c & 对匹配模式取反，即搜索不匹配行而不是匹配行 \\
\hline
\end{tabular}
\end{table}

\end{document}